import mapboxgl from 'mapbox-gl';
import React, {
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from 'react';
import { createPortal } from 'react-dom';
import type Mapless from '../../Mapless';
import ErrorBoundary from '../ErrorBoundary';
import styles from './index.module.less';

// 定义 MapboxPopup 组件的 props 类型
type MapboxPopupProps = {
  maplessRef?: React.RefObject<Mapless | undefined>;
  lngLat: mapboxgl.LngLatLike;
  children: React.ReactNode;
  onClose?: () => void;
};

export interface MapboxPopupRef {
  show: () => void;
  hide: () => void;
}

const MapboxPopup = forwardRef(
  ({ maplessRef, lngLat, children, onClose }: MapboxPopupProps, ref) => {
    const popupRef = useRef<mapboxgl.Popup>(undefined);
    const popupNodeRef = useRef(document.createElement('div'));

    const [show, setShow] = useState(false);

    useImperativeHandle(
      ref,
      () => ({
        show: () => setShow(true),
        hide: () => setShow(false),
      }),
      [],
    );

    const handlePopupClose = useCallback(() => {
      setShow(false);
      onClose?.();
    }, [onClose]);

    useEffect(() => {
      const { map } = maplessRef?.current || {};
      if (!map) return;
      popupRef.current?.remove();
      if (show) {
        if (!popupRef.current) {
          popupRef.current = new mapboxgl.Popup({
            closeOnMove: false,
            closeOnClick: false,
            className: styles['react-popup'],
            focusAfterOpen: false,
          })
            .setLngLat(lngLat)
            .setDOMContent(popupNodeRef.current)
            .addTo(map);
          popupRef.current.on('close', handlePopupClose);
        }
        popupRef.current.fire('open');
      } else {
        popupRef.current?.fire('close');
      }
      return () => {
        popupRef.current?.remove();
        popupRef.current = undefined;
      };
    }, [maplessRef?.current, show]);

    useEffect(() => {
      if (popupRef.current) {
        popupRef.current?.setLngLat(lngLat);
      }
    }, [JSON.stringify(lngLat)]);

    return (
      <ErrorBoundary message="MapboxMarker">
        {createPortal(children, popupNodeRef.current)}
      </ErrorBoundary>
    );
  },
);

function isEqual(
  prev: Readonly<MapboxPopupProps>,
  next: Readonly<MapboxPopupProps>,
): boolean {
  return (
    JSON.stringify(prev.lngLat) === JSON.stringify(next.lngLat) &&
    prev.children === next.children
  );
}

export default React.memo(MapboxPopup, isEqual);
